package gops

import (
    "context"
    "github.com/redis/go-redis/v9"
    "time"
)

type redisClientInterface interface {
    Exists(key string) bool
    Del(key string) error
    Set(key string, value interface{}, expiration time.Duration) error
    Get(key string) (string, error)
    Expire(key string, expiration time.Duration) error
    LPush(key string, values ...interface{}) error
    RPush(key string, values ...interface{}) error
    LPop(key string) (string, error)
    RPop(key string) (string, error)
    LLen(key string) (int64, error)
    HSet(key string, fields map[string]interface{}) error
    HGet(key, field string) (string, error)
    HDel(key string, fields ...string) error
    HGetAll(key string) (map[string]string, error)
}

// redisClientStruct 是 Redis 操作的封装结构体
type redisClientStruct struct {
    ctx    context.Context
    client *redis.Client
}

// NewRedisClient 创建一个新的 RedisClient 实例
func NewRedisClient(host, port, password string, db int) redisClientInterface {
    rdb := redis.NewClient(&redis.Options{
        Addr:     host + ":" + port,
        Password: password,
        DB:       db,
        PoolSize: 10, // 根据需求调整连接池大小
    })

    return &redisClientStruct{
        ctx:    context.Background(),
        client: rdb,
    }
}

// Exists 判断key是否存在
func (c *redisClientStruct) Exists(key string) bool {
    // 1表示存在, 0表示不存在
    number, err := c.client.Exists(c.ctx, key).Result()
    if err != nil {
        return false
    } else {
        if number == 1 {
            return true
        } else {
            return false
        }
    }
}

// Del 删除一个 key
func (c *redisClientStruct) Del(key string) error {
    if !c.Exists(key) {
        return nil
    } else {
        err := c.client.Del(c.ctx, key).Err()
        if err != nil {
            return err
        } else {
            return nil
        }
    }
}

// String 相关操作

// Set 设置一个 string 类型的 key-value
func (c *redisClientStruct) Set(key string, value interface{}, expiration time.Duration) error {
    return c.client.Set(c.ctx, key, value, expiration).Err()
}

// Get 获取 string 类型的 key 值
func (c *redisClientStruct) Get(key string) (string, error) {
    return c.client.Get(c.ctx, key).Result()
}

// Expire 为 key 设置过期时间
func (c *redisClientStruct) Expire(key string, expiration time.Duration) error {
    return c.client.Expire(c.ctx, key, expiration).Err()
}

// List 操作

// LPush 在 list 左侧插入元素
func (c *redisClientStruct) LPush(key string, values ...interface{}) error {
    return c.client.LPush(c.ctx, key, values...).Err()
}

// RPush 在 list 右侧插入元素
func (c *redisClientStruct) RPush(key string, values ...interface{}) error {
    return c.client.RPush(c.ctx, key, values...).Err()
}

// LPop 从 list 左侧弹出元素
func (c *redisClientStruct) LPop(key string) (string, error) {
    return c.client.LPop(c.ctx, key).Result()
}

// RPop 从 list 右侧弹出元素
func (c *redisClientStruct) RPop(key string) (string, error) {
    return c.client.RPop(c.ctx, key).Result()
}

// LLen 获取 list 长度
func (c *redisClientStruct) LLen(key string) (int64, error) {
    return c.client.LLen(c.ctx, key).Result()
}

// Hash 操作

// HSet 设置 hash 中的多个字段
func (c *redisClientStruct) HSet(key string, fields map[string]interface{}) error {
    return c.client.HSet(c.ctx, key, fields).Err()
}

// HGet 获取 hash 中指定字段的值
func (c *redisClientStruct) HGet(key, field string) (string, error) {
    return c.client.HGet(c.ctx, key, field).Result()
}

// HDel 删除 hash 中的一个或多个字段
func (c *redisClientStruct) HDel(key string, fields ...string) error {
    return c.client.HDel(c.ctx, key, fields...).Err()
}

// HGetAll 获取 hash 中的所有字段和值
func (c *redisClientStruct) HGetAll(key string) (map[string]string, error) {
    return c.client.HGetAll(c.ctx, key).Result()
}

//func main() {
// ctx作用: 控制Goroutine的取消和超时，确保资源及时释放；传递请求范围的数据，如用户身份或请求ID；支持链式取消，父上下文取消后子上下文自动取消；还有在微服务中用于链路追踪等。
// ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
// defer cancel()
// err := client.Set(ctx, "key", "value", 0)
// if err != nil {
// log.Println("操作超时或被取消")
//}

//    client := NewClient("192.168.4.54", "6379", "", 0)
//    client.Set(context.Background(), "key", "value", 0)
//    client.Del(context.Background(), "key")
//
//    client.Expire(context.Background(), "key", 10*time.Second)
//}
